package com.maple.webrtc.ui

import android.os.Bundle
import android.widget.ListView
import androidx.appcompat.app.AppCompatActivity
import com.maple.webrtc.R
import com.maple.webrtc.app.Const
import com.maple.webrtc.core.PeerConnectionObserverAdapter
import com.maple.webrtc.core.SdpObserverAdapter
import com.maple.webrtc.socket.EventCode
import com.maple.webrtc.socket.Server
import com.maple.webrtc.socket.SocketType
import com.maple.webrtc.utils.LogUtils
import com.maple.webrtc.utils.WebRTCUtils
import org.json.JSONObject
import org.webrtc.AudioSource
import org.webrtc.AudioTrack
import org.webrtc.CameraVideoCapturer
import org.webrtc.DefaultVideoDecoderFactory
import org.webrtc.EglBase
import org.webrtc.IceCandidate
import org.webrtc.MediaConstraints
import org.webrtc.PeerConnection
import org.webrtc.PeerConnection.IceConnectionState
import org.webrtc.PeerConnection.RTCConfiguration
import org.webrtc.PeerConnectionFactory
import org.webrtc.RtpTransceiver
import org.webrtc.RtpTransceiver.RtpTransceiverInit
import org.webrtc.SessionDescription
import org.webrtc.SurfaceTextureHelper
import org.webrtc.SurfaceViewRenderer
import org.webrtc.VideoSource
import org.webrtc.VideoTrack
import org.webrtc.createCustomVideoEncoderFactory
import java.util.concurrent.ConcurrentHashMap

class CameraActivity : AppCompatActivity() {


    private var lvList: ListView? = null
    private var localRenderer: SurfaceViewRenderer? = null

    private lateinit var peerConnectionFactory: PeerConnectionFactory

    private val peerConnections = ConcurrentHashMap<String, PeerConnection>()

    private var cameraVideoCapturer: CameraVideoCapturer? = null

    private var videoTrack: VideoTrack? = null
    private var audioTrack: AudioTrack? = null

    private val eglBaseContext = EglBase.create().eglBaseContext


    private val listAdapter: MessageAdapter by lazy {
        MessageAdapter(this)
    }

    private val callback: Server.Callback by lazy {
        object: Server.Callback{
            override fun onListen(host: String) {
                addItemList("监听->${host}")
            }

            override fun onClientConnected(host: String) {
                addItemList("客户端->${host} 已连接")
            }

            override fun onReceive(json: JSONObject) {
                addItemList("收到消息->${json}")
               val eventCode = json.getString("eventCode")
                if(eventCode.equals(EventCode.JOIN.name)) {
                    val user = json.getString("user")
                    createOffer(user)
                } else if(eventCode.equals(EventCode.ANSWER.name)) {
                    parseAnswer(json)
                } else if(eventCode.equals(EventCode.ICE_CANDIDATE.name)) {
                    parseIceCandidate(json)
                }
            }
        }
    }


    private val server: Server by lazy {
        Server(this, Const.SERVER_PORT).apply {
            this.setCallback(callback)
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_camera)
        lvList = findViewById(R.id.lv_list)
        localRenderer = findViewById(R.id.svr_local_renderer)
        localRenderer?.init(eglBaseContext, null)
        localRenderer?.setMirror(true)
        lvList?.adapter = listAdapter
        server.start()

        initRTC()
    }


    private fun initRTC() {
        val options = PeerConnectionFactory.Options()

        val encoderFactory = createCustomVideoEncoderFactory(eglBaseContext, true, true) { true }
        val decoderFactory = DefaultVideoDecoderFactory(eglBaseContext)
        peerConnectionFactory = PeerConnectionFactory
            .builder()
            .setOptions(options)
            .setVideoEncoderFactory(encoderFactory)
            .setVideoDecoderFactory(decoderFactory)
            .createPeerConnectionFactory()

        val createAudioSource: AudioSource? = peerConnectionFactory.createAudioSource(WebRTCUtils.buildAudioConstraints())
        audioTrack = peerConnectionFactory.createAudioTrack("local_audio_track", createAudioSource)
        cameraVideoCapturer = WebRTCUtils.createVideoCapture(this)

        if (cameraVideoCapturer != null) {
            val videoSource: VideoSource = peerConnectionFactory.createVideoSource(cameraVideoCapturer!!.isScreencast)
            val surfaceTextureHelper = SurfaceTextureHelper.create("surface_texture_thread", eglBaseContext)
            cameraVideoCapturer!!.initialize(surfaceTextureHelper, this, videoSource.capturerObserver)
            //使用720P的分辨率
            cameraVideoCapturer!!.startCapture(localRenderer!!.width, localRenderer!!.height, 20)
            videoTrack = peerConnectionFactory.createVideoTrack("local_video_track", videoSource)
             videoTrack?.addSink(localRenderer);
        }
    }

    private fun addItemList(item: String) {
        listAdapter.addItem(item)
        lvList?.smoothScrollToPosition(listAdapter.dataList.size - 1)
    }

    private fun createOffer(user: String) {
        val rtcConfig: RTCConfiguration = WebRTCUtils.createRTCConfiguration()
        val peerConnection = peerConnectionFactory.createPeerConnection(rtcConfig, object : PeerConnectionObserverAdapter(SocketType.CAMERA.name) {
            override fun onIceConnectionChange(iceConnectionState: IceConnectionState?) {
                super.onIceConnectionChange(iceConnectionState)
                LogUtils.logGGQ("camera onIceConnectionChange")
            }
        })

        peerConnection?.let { peer ->
            videoTrack?.let {
                peer.addTransceiver(it, RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.SEND_ONLY))
            }
            audioTrack?.let {
                peer.addTransceiver(it, RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.SEND_ONLY))
            }
            peerConnections.put(user,peer)

            peer.createOffer(object :SdpObserverAdapter("createOffer") {
                override fun onCreateSuccess(sdp: SessionDescription?) {
                    super.onCreateSuccess(sdp)
                    if (sdp != null && sdp.type == SessionDescription.Type.OFFER) {
                        peer.setLocalDescription(SdpObserverAdapter("setLocalDescription"), sdp)
                        // offer 发送 sdp 给 app
                        val offerJson = JSONObject()
                        offerJson.put("eventCode",EventCode.OFFER.name)
                        offerJson.put("user",user)
                        offerJson.put("type",sdp.type)
                        offerJson.put("sdp",sdp.description)
                        server.send(offerJson)
                    }
                }
            },MediaConstraints())
        }
    }

    private fun parseAnswer(json: JSONObject) {
        peerConnections.get(json.getString("user"))?.let { peer ->
            val answerSdpDescription = json.getString("sdp")
            val answerSdp = SessionDescription(SessionDescription.Type.ANSWER, answerSdpDescription)
            peer.setRemoteDescription(object :SdpObserverAdapter("setRemoteDescription"){},answerSdp)
        }
    }

    private fun parseIceCandidate(json: JSONObject) {
        peerConnections.get(json.getString("user"))?.let { peer ->
            val candidate = json.getString("candidate")
            val sdpMid = json.getString("sdpMid")
            val sdpMLineIndex = json.getInt("sdpMLineIndex")
            val iceCandidate = IceCandidate(sdpMid, sdpMLineIndex, candidate)
            peer.addIceCandidate(iceCandidate)
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        audioTrack?.let {
            it.dispose()
        }
        videoTrack?.let {
            it.dispose()
        }
        cameraVideoCapturer?.let {
            it.stopCapture()
            it.dispose()
        }
        peerConnections.forEach {
            it.value.dispose()
        }
        localRenderer?.let {
            it.release()
        }
        server.stop()
        peerConnectionFactory.dispose()
    }
}